home *** CD-ROM | disk | FTP | other *** search
/ MIDICraft's MIDINET CD-ROM / MIDICraft's MIDINET CD-ROM.iso / DOSUTILS / MIDISORT / MIDISORT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-11  |  8.7 KB  |  400 lines

  1. // midisort v1.0 written by Günter Nagler 1995 (gnagler@ihm.tu-graz.ac.at)
  2. #include "midiio.hpp"
  3. #include "mtrack.hpp"
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <assert.h>
  7. #include <ctype.h>
  8. #ifdef __MSDOS__
  9. #include <alloc.h>
  10. #endif
  11.  
  12. class MidiCopyTrack;
  13.  
  14. char* input = 0;
  15. char* output = 0;
  16.  
  17. #define MAXTRACKS  150
  18.  
  19. int sortbychannel = 0;
  20. int moveempty = 0;
  21. int manualorder[MAXTRACKS];
  22. int manualcnt = 0;
  23. int showtracks = 0;
  24. int order[MAXTRACKS];
  25.  
  26. MidiWrite* write = 0;
  27. MidiTrackinfo* info = 0;
  28.  
  29. class MidiCopyTrack : public MidiRead
  30. {
  31. public:
  32.   MidiCopyTrack(char* name, FILE* f = 0);
  33.  
  34.   virtual void track(int trackno, long length, int channel);
  35.   virtual void endtrack(int trackno);
  36.   virtual void time(unsigned long ticks);
  37.  
  38.   virtual void program(int prg, int channel);
  39.   virtual void control(int channel, int what, int value);
  40.   virtual void noteon(int channel, int note, int vel);
  41.   virtual void noteoff(int channel, int note, int vel);
  42.   virtual void pitchbend(int channel, int val);
  43.   virtual void polyaftertouch(int channel, int note, int val);
  44.   virtual void aftertouch(int channel, int val);
  45.   virtual void songpos(unsigned pos);
  46.   virtual void songselect(unsigned char song);
  47.   virtual void tunerequest();
  48.   virtual void timingclock();
  49.   virtual void start();
  50.   virtual void cont();
  51.   virtual void stop();
  52.   virtual void activesense();
  53.   virtual void sysex(int syslen, unsigned char* sysdata);
  54.   virtual void meta(int what, int len, unsigned char* data);
  55.   virtual void error(const char* msg);
  56. };
  57.  
  58. MidiCopyTrack::MidiCopyTrack(char* name, FILE* f) : MidiRead(name, f)
  59. {
  60.   options_ = OPTION_NOCONTROLS+OPTION_NOSYSEVENTS;
  61. }
  62.  
  63. void MidiCopyTrack::track(int trackno, long length, int channel)
  64. {
  65.   write->track();
  66. }
  67.  
  68. void MidiCopyTrack::endtrack(int trackno)
  69. {
  70.   write->endtrack();
  71. }
  72.  
  73. void MidiCopyTrack::time(unsigned long ticks)
  74. {
  75.   write->time(ticks);
  76. }
  77.  
  78.  
  79. void MidiCopyTrack::meta(int what, int len, unsigned char* data)
  80. {
  81.   write->meta(what, len, data);
  82. }
  83.  
  84. void MidiCopyTrack::program(int channel, int prg)
  85. {
  86.   write->program(channel, prg);
  87. }
  88.  
  89. void MidiCopyTrack::control(int channel, int what, int value)
  90. {
  91.   write->control(channel, what, value);
  92. }
  93.  
  94. void MidiCopyTrack::noteon(int channel, int note, int vel)
  95. {
  96.   write->noteon(channel, note, vel);
  97. }
  98.  
  99. void MidiCopyTrack::noteoff(int channel, int note, int vel)
  100. {
  101.   write->noteoff(channel, note, vel);
  102. }
  103.  
  104. void MidiCopyTrack::pitchbend(int channel, int val)
  105. {
  106.   write->pitchbend(channel, val);
  107. }
  108.  
  109. void MidiCopyTrack::polyaftertouch(int channel, int note, int val)
  110. {
  111.   write->polyaftertouch(channel, note, val);
  112. }
  113.  
  114. void MidiCopyTrack::aftertouch(int channel, int val)
  115. {
  116.   write->aftertouch(channel, val);
  117. }
  118.  
  119. void MidiCopyTrack::songpos(unsigned pos)
  120. {
  121.   write->songpos(pos);
  122. }
  123.  
  124. void MidiCopyTrack::songselect(unsigned char song)
  125. {
  126.   write->songselect(song);
  127. }
  128.  
  129. void MidiCopyTrack::tunerequest()
  130. {
  131.   write->tunerequest();
  132. }
  133.  
  134. void MidiCopyTrack::timingclock()
  135. {
  136.   write->timingclock();
  137. }
  138.  
  139. void MidiCopyTrack::start()
  140. {
  141.   write->start();
  142. }
  143.  
  144. void MidiCopyTrack::cont()
  145. {
  146.   write->cont();
  147. }
  148.  
  149. void MidiCopyTrack::stop()
  150. {
  151.   write->stop();
  152. }
  153.  
  154. void MidiCopyTrack::activesense()
  155. {
  156.   write->activesense();
  157. }
  158.  
  159. void MidiCopyTrack::sysex(int syslen, unsigned char* sysdata)
  160. {
  161.   write->sysex(syslen, sysdata);
  162. }
  163.  
  164. void MidiCopyTrack::error(const char* msg)
  165. {
  166.   printf("// error: %s\n", msg);
  167.   exit(1);
  168. }
  169.  
  170.  
  171. void movetrack(int from, int to)
  172. {
  173.   if (from == to)
  174.     return;
  175.   int t = order[from];
  176.  
  177.   if (from > to)
  178.   {
  179.  
  180.     for (int i = from; i > to; i--)
  181.       order[i] = order[i-1];
  182.     order[i] = t;
  183.   }
  184.   else if (to > from)
  185.   {
  186.     for (int i = from; i < to; i++)
  187.       order[i] = order[i+1];
  188.     order[i] = t;
  189.   }
  190. }
  191.  
  192. void midisort()
  193. {
  194. int trk;
  195.  
  196.   if (info->trackcount() >= MAXTRACKS)
  197.   {
  198.     fprintf(stderr, "Too many tracks. Cannot sort\n");
  199.     exit(1);
  200.   }
  201.   for (trk = 0; trk < info->trackcount(); trk++)  // default: no sorting
  202.     order[trk] = trk+1;
  203.  
  204.   if (manualcnt > 0)
  205.   {
  206.   int n = 1;
  207.  
  208.     // manual order
  209.     for (int i = 0; i < manualcnt; i++)
  210.     {
  211.       // search for duplicates
  212.       for (int j = i+1; j < manualcnt; j++)
  213.       if (manualorder[j] == manualorder[i])
  214.     break;
  215.       if (j < manualcnt)
  216.     continue;  // ignore duplicate order numbers
  217.  
  218.       if (i > 0 && manualorder[i] == 1)
  219.       {
  220.     fprintf(stderr, "track 1 cannot be moved!\n");
  221.     continue;
  222.       }
  223.       // search for current track order
  224.       for (j = 0; j < info->trackcount(); j++)
  225.       if (manualorder[i] == order[j])
  226.     break;
  227.       if (j >= info->trackcount())  // track does not exist
  228.     continue;
  229.       movetrack(j, n++);
  230.     }
  231.     // other tracks remain the same
  232.   }
  233.   if (moveempty)
  234.   {
  235.     // move empty comment tracks to end of midi file
  236.     // reason: some players limit number of tracks and then
  237.     // empty tracks are loaded and important are ommitted
  238.     for (trk = 1; trk < info->trackcount(); trk++)
  239.     {
  240.       // order[1..trk-1] have channel != NOCHANNEL!
  241.  
  242.       int k;
  243.  
  244.       for (k = trk; k < info->trackcount(); k++)
  245.       if (info->trackinfo(order[k])->channel_ != NOCHANNEL)
  246.     break;
  247.       if (k >= info->trackcount())
  248.     break;
  249.  
  250.       movetrack(k, trk);
  251.     }
  252.   }
  253.  
  254.   if (sortbychannel)
  255.   {
  256.     for (trk = 1; trk < info->trackcount(); trk++)
  257.     if (info->trackinfo(order[trk])->channel_ >= 0)
  258.     {
  259.       // order[1..trk-1] are sorted!
  260.  
  261.       int k, bestk;
  262.  
  263.       bestk = -1;
  264.       for (k = trk; k < info->trackcount(); k++)
  265.       if (info->trackinfo(order[k])->channel_ >= 0)
  266.       {
  267.     if (bestk < 0 ||
  268.       info->trackinfo(order[k])->channel_ < info->trackinfo(order[bestk])->channel_)
  269.     {
  270.       bestk = k;
  271.     }
  272.       }
  273.       if (bestk < 0)
  274.     break;
  275.       movetrack(bestk, trk);
  276.     }
  277.   }
  278.  
  279.   assert(order[0] == 1);  // do not move first track!
  280.  
  281.   for (trk = 0; trk < info->trackcount(); trk++)
  282.   if (order[trk] != trk+1)
  283.     break;
  284.   if (trk >= info->trackcount())
  285.     fprintf(stderr, "Tracks of %s are already sorted. Building a safe copy.\n", input);
  286.  
  287.   write = new MidiWrite(output); assert(write != 0);
  288.   write->head(info->version_,0, info->unitsperbeat_);
  289.  
  290.   MidiCopyTrack copy(input);
  291.   for (trk = 0; trk < info->trackcount(); trk++)
  292.   {
  293. //    printf("writing track #%d\n", order[trk]);
  294.     copy.seek(info->trackinfo(order[trk])->pos_);
  295.     copy.runtrack(trk+1);
  296.   }
  297.   delete write;  // close midi file
  298.   fprintf(stderr, "output written to %s\n", output);
  299. }
  300.  
  301. void usage()
  302. {
  303.   fprintf(stderr, "usage: midisort [-track] [-order # ...] [-channel][-moveempty] srcfile.mid dstfile.mid\n");
  304.   fprintf(stderr, "sorts tracks of a midi file or generates a duplicate.\n");
  305.   fprintf(stderr, "-track\t\tshow tracks\n");
  306.   fprintf(stderr, "-order # ...\tdefine order of tracks (e.g. 1 3 2)\n");
  307.   fprintf(stderr, "-channel\tsort by channel numbers\n");
  308.   fprintf(stderr, "-moveempty\tmove empty or comment tracks to end of midi\n");
  309.   exit(1);
  310. }
  311.  
  312. int main(int argc, char** argv)
  313. {
  314.   argc--; argv++;
  315.  
  316.   while (argc > 0 && **argv == '-')
  317.   {
  318.     if (strncmp(*argv, "-track", 2) == 0)
  319.     {
  320.       showtracks = 1;
  321.       argc--; argv++; continue;
  322.     }
  323.     else if (strncmp(*argv, "-channel", 2) == 0)
  324.     {
  325.       sortbychannel = 1;
  326.       argc--; argv++; continue;
  327.     }
  328.     else if (strncmp(*argv, "-moveempty", 2) == 0)
  329.     {
  330.       moveempty = 1;
  331.       argc--; argv++; continue;
  332.     }
  333.     else if (strncmp(*argv, "-order", 2) == 0)
  334.     {
  335.       argc--; argv++;
  336.       if (argc == 0 || !isdigit(**argv))
  337.     fprintf(stderr, "option -order needs tracknumbers as parameters\n");
  338.       while (argc > 0 && isdigit(**argv) && manualcnt < MAXTRACKS)
  339.       {
  340.       int order;
  341.  
  342.     if (sscanf(*argv, "%d", &order) != 1)
  343.     {
  344.       fprintf(stderr, "parameters of option -order must be numbers between 1 and %d\n",
  345.          MAXTRACKS);
  346.       exit(1);
  347.     }
  348.     else if (order <= 0)
  349.     {
  350.       fprintf(stderr, "invalid order number %s (should be 1..%d)\n",
  351.         *argv, MAXTRACKS);
  352.       exit(1);
  353.     }
  354.     else
  355.     {
  356.       manualorder[manualcnt++] = order;
  357.     }
  358.     argc--; argv++;
  359.       }
  360.       continue;
  361.     }
  362.     fprintf(stderr, "invalid option %s\n", *argv);
  363.     argc--; argv++;
  364.     usage();
  365.   }
  366.  
  367.   if (argc <= 0)
  368.     usage();
  369.  
  370.   input = *argv++; argc--;
  371.   info = new MidiTrackinfo(input); assert(info != 0);
  372.   if (!info->getf())
  373.   {
  374.     fprintf(stderr, "could not open %s\n", input);
  375.     delete info;
  376.     exit(1);
  377.   }
  378.  
  379.   if (showtracks)
  380.   {
  381.     info->print(stdout);
  382.     delete info;
  383.     exit(0);
  384.   }
  385.  
  386.   if (argc <= 0)
  387.     usage();
  388.  
  389.   output = *argv++; argc--;
  390.   if (strcmp(input, output) == 0)
  391.   {
  392.     fprintf(stderr, "cannot sort midi to same file\n");
  393.     return 1;
  394.   }
  395.  
  396.   midisort();
  397.  
  398.   delete info;
  399.   return 0;
  400. }